//**************************************************************************
// Copyright 2008 Peter Project (http://www.codeplex.com/peter)
//
// License : GNU General Public License (GPL)
// For full text of the license please goto:
// http://www.gnu.org/licenses/gpl-2.0.html
//
// This code is provided on an AS IS basis, with no WARRANTIES,
// CONDITIONS or GUARANTEES of any kind.
//
//		File: PeterInterfaces.cs
//		Purpose: This file holds all the Interfaces for the Peter
//				 Plugin Architecture.
//
//**************************************************************************

using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using PeterInterface;
using WeifenLuo.WinFormsUI.Docking;

namespace Peter
{
    public delegate void LoadFileDelegate(string text);
    public delegate void CloseDelegate();

    public class Editor : DockContent, IPeterPluginTab, IHtmlInterface
    {
        private TextEditorControl m_Editor;
        private IPeterPluginHost m_Host;
        private bool m_Changed;
        private int m_FindPos;
        private MainForm m_MainForm;
        private FileSystemWatcher m_FSW;
        private LoadFileDelegate m_LoadFile;
        private CloseDelegate m_CloseDel;
        private cHtmlToolTip m_ToolTip;
        private string m_Project;
        private GListBox m_AutoComplete;

        #region -= Constructor =-

        public Editor(string tabTitle, MainForm main)
        {
            // Set up the Parent Tab...
            this.TabText = tabTitle;
            this.m_FindPos = -1;
            this.m_MainForm = main;
            this.m_ToolTip = new cHtmlToolTip(this);
            this.m_Project = "";
            this.m_AutoComplete = new GListBox();

            // Set up the Editor...
            this.m_Editor = new TextEditorControl();
            this.m_Editor.Dock = System.Windows.Forms.DockStyle.Fill;

            // Add the Editor...
            this.Controls.Add(this.m_Editor);
            this.m_Changed = false;

            // Delegates...
            this.m_LoadFile = new LoadFileDelegate(this.DelReLoad);
            this.m_CloseDel = new CloseDelegate(this.DelClose);

            // Drag N Drop...
            this.m_Editor.ActiveTextAreaControl.TextArea.AllowDrop = true;
            this.m_Editor.ActiveTextAreaControl.TextArea.DragEnter += new System.Windows.Forms.DragEventHandler(TextArea_DragEnter);
            this.m_Editor.ActiveTextAreaControl.TextArea.DragDrop += new System.Windows.Forms.DragEventHandler(TextArea_DragDrop);
            this.m_Editor.ActiveTextAreaControl.TextArea.MouseDown += new MouseEventHandler(TextArea_MouseDown);
            this.m_Editor.ActiveTextAreaControl.Caret.PositionChanged += new EventHandler(Caret_Change);
            this.m_Editor.ActiveTextAreaControl.Caret.CaretModeChanged += new EventHandler(Caret_CaretModeChanged);
            this.m_Editor.ActiveTextAreaControl.TextArea.LostFocus += new EventHandler(TextArea_LostFocus);
            this.m_Editor.ActiveTextAreaControl.TextArea.KeyDown += new System.Windows.Forms.KeyEventHandler(TextArea_KeyDown);
            this.m_Editor.Document.DocumentChanged += new DocumentEventHandler(Document_DocumentChanged);
            this.m_Editor.Document.UndoStack.ActionRedone += new EventHandler(UndoStack_ActionRedone);
            this.m_Editor.Document.UndoStack.ActionUndone += new EventHandler(UndoStack_ActionRedone);
        }

        #endregion

        #region -= Key Press =-
   
        void TextArea_KeyDown (object sender, KeyEventArgs e)
        {
            /* Auto Complete...
            if (this.Controls.Contains(this.m_AutoComplete))
            {
                switch (e.KeyCode)
                {
                    case Keys.Enter:
                    case Keys.Space:
                    case Keys.Oemcomma:
                    case Keys.OemMinus:
                    case Keys.OemOpenBrackets:
                    case Keys.OemPeriod:
                    case Keys.Oemplus:
                    case Keys.OemSemicolon:
                        this.Controls.Remove(this.m_AutoComplete);
                        break;
                }
            }
            /*if (e.KeyCode == Keys.OemPeriod)
            {
                this.Controls.Add(this.m_AutoComplete);
                this.m_AutoComplete.Location = new Point(this.m_Editor.ActiveTextAreaControl.Caret.ScreenPosition.X, 
                    this.m_Editor.ActiveTextAreaControl.Caret.ScreenPosition.Y + this.m_Editor.Font.Height);
                this.m_AutoComplete.Size = new Size(100, 100);
                this.m_AutoComplete.BringToFront();
                this.m_AutoComplete.Show();
            }
            else
            {
                if (this.Controls.Contains(this.m_AutoComplete))
                {
                    this.Controls.Remove(this.m_AutoComplete);
                }
            }*/
        }

        #endregion

        #region -= Caret =-

        void Caret_CaretModeChanged(object sender, EventArgs e)
        {
            this.UpdateCaretPos();
        }

        void Caret_Change(object sender, EventArgs e)
        {
            this.UpdateCaretPos();
        }

        public void UpdateCaretPos()
        {
            this.m_MainForm.UpdateCaretPos(this.m_Editor.ActiveTextAreaControl.Caret.Offset, this.m_Editor.ActiveTextAreaControl.Caret.Line + 1,
                this.m_Editor.ActiveTextAreaControl.Caret.Column + 1, this.m_Editor.ActiveTextAreaControl.Caret.CaretMode.ToString());
        }

        #endregion

        #region -= Mouse Down =-

        void TextArea_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.m_ToolTip.Visible) this.m_ToolTip.Hide();
            if (e.Button == MouseButtons.Left)
            {
                if (Control.ModifierKeys == Keys.Control || Control.ModifierKeys == Keys.Alt)
                {
                    int pos = this.m_Editor.ActiveTextAreaControl.Caret.Offset;
                    int before = pos;
                    int after = pos;
                    while (CheckStop(this.m_Editor.Document.TextContent[before]))
                    {
                        before--;
                    }
                    before++;
                    while (CheckStop(this.m_Editor.Document.TextContent[after]))
                    {
                        after++;
                    }

                    if (after > before)
                    {
                        if (Control.ModifierKeys == Keys.Control)
                        {
                            this.m_Editor.ActiveTextAreaControl.SelectionManager.SetSelection(
                                this.m_Editor.Document.OffsetToPosition(before), this.m_Editor.Document.OffsetToPosition(after));
                        }
                        else if (Control.ModifierKeys == Keys.Alt)
                        {
                            #region -= Look Up Word =-

                            string text = this.m_Editor.Document.TextContent.Substring(before, after - before);
                            string html = "<table><tr><th colspan=\"2\">" + text + "</th></tr><tr>";
                            int count = 0;
                            if (!string.IsNullOrEmpty(this.m_Project))
                            {
                                string lookup = this.m_MainForm.LookUpProject(text, this.m_Project);
                                if (!lookup.Equals("<ul></ul>"))
                                {
                                    count++;
                                }
                                html += "<tr><td colspan=\"2\">" + lookup + "</td></tr>";
                            }
                            Regex reg = new Regex(text);
                            MatchCollection mc = reg.Matches(this.m_Editor.Document.TextContent);
                            if (mc.Count > 1)
                            {
                                ArrayList lines = new ArrayList();
                                html += "<tr><td colspan=\"2\">References in Document:</td></tr>";
                                foreach (Match m in mc)
                                {
                                    int lineNum = this.m_Editor.Document.GetLineNumberForOffset(m.Index);
                                    if (lineNum != this.m_Editor.ActiveTextAreaControl.Caret.Line && !lines.Contains(lineNum))
                                    {
                                        lines.Add(lineNum);
                                        lineNum++;
                                        count++;
                                        LineSegment line = this.m_Editor.Document.GetLineSegmentForOffset(m.Index);

                                        html += "<tr><td valign=\"top\" align=\"right\"><a href=\"\">" + lineNum.ToString() + "</a></td><td>" + 
                                            this.m_Editor.Document.TextContent.Substring(line.Offset, line.TotalLength) + "</td></tr>";
                                    }
                                }
                                html += "</table>";
                            }
                            if (count > 0)
                            {
                                this.m_ToolTip.HTML = html;
                                this.m_ToolTip.Location = MousePosition;
                                this.m_ToolTip.Show();
                            }

                            #endregion
                        }
                    }
                }
            }
        }

        #endregion

        #region -= Check Stop =-

        private bool CheckStop(char val)
        {
            switch (val)
            {
                case '(':
                case ')':
                case ' ':
                case '-':
                case '+':
                case '=':
                case '*':
                case '&':
                case '^':
                case '%':
                case '$':
                case '#':
                case '@':
                case '!':
                case '{':
                case '}':
                case '[':
                case ']':
                case '|':
                case '\\':
                case ';':
                case '\'':
                case ':':
                case '\"':
                case ',':
                case '.':
                case '<':
                case '>':
                case '/':
                case '?':
                case '`':
                case '~':
                case '\t':
                case '\r':
                case '\n':
                    return false;
                default:
                    return true;
            }
        }

        #endregion

        #region -= Misc =-

        void UndoStack_ActionRedone(object sender, EventArgs e)
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.Invalidate();
        }

        /// <summary>
        /// Sets the Context Menu for the Editor
        /// </summary>
        /// <param name="ctx">Context Menu to use.</param>
        public void SetContextMenuStrip(ContextMenuStrip ctx)
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ContextMenuStrip = ctx;
        }

        public void Print()
        {
            PrintPreviewDialog dlg = new PrintPreviewDialog();
            dlg.Document = this.m_Editor.PrintDocument;
            dlg.ShowDialog();
        }

        public void ScrollTo(int offset)
        {
            if (offset > this.m_Editor.Document.TextLength)
            {
                return;
            }
            int line = this.m_Editor.Document.GetLineNumberForOffset(offset);
            this.m_Editor.ActiveTextAreaControl.Caret.Position = this.m_Editor.Document.OffsetToPosition(offset);
            this.m_Editor.ActiveTextAreaControl.ScrollTo(line);//.CenterViewOn(line, 0);
        }

        void TextArea_LostFocus (object sender, EventArgs e)
        {
            if (this.m_ToolTip.Visible) this.m_ToolTip.Hide();
        }

        /// <summary>
        /// Gets or Sets the Project related to the file...
        /// </summary>
        public string Project
        {
            get { return this.m_Project; }

            set { this.m_Project = value; }
        }

        #endregion

        #region -= File Watcher =-

        /// <summary>
        /// Sets up the file watcher...
        /// </summary>
        public void SetupFileWatcher()
        {
            // Remove Events...
            if (this.m_FSW != null)
            {
                this.m_FSW.Changed -= new FileSystemEventHandler(m_FSW_Changed);
                this.m_FSW.Deleted -= new FileSystemEventHandler(m_FSW_Deleted);
                this.m_FSW.Renamed -= new RenamedEventHandler(m_FSW_Renamed);
            }

            // Create new FileWatcher...
            this.m_FSW = new FileSystemWatcher(Path.GetDirectoryName(this.m_Editor.FileName), Path.GetFileName(this.m_Editor.FileName));
            this.m_FSW.EnableRaisingEvents = true;
            this.m_FSW.IncludeSubdirectories = false;

            // Add Events...
            this.m_FSW.Changed += new FileSystemEventHandler(m_FSW_Changed);
            this.m_FSW.Deleted += new FileSystemEventHandler(m_FSW_Deleted);
            this.m_FSW.Renamed += new RenamedEventHandler(m_FSW_Renamed);
        }

        /// <summary>
        /// Occurs when the file is Renamed...
        /// </summary>
        /// <param name="sender">FileSystemWatcher</param>
        /// <param name="e">Events</param>
        void m_FSW_Renamed(object sender, RenamedEventArgs e)
        {
            this.Invoke(this.m_LoadFile, new object[] { e.FullPath });
        }

        /// <summary>
        /// Occurs when the file is Changed...
        /// </summary>
        /// <param name="sender">FileSystemWatcher</param>
        /// <param name="e">Events</param>
        void m_FSW_Changed (object sender, FileSystemEventArgs e)
        {
            this.Invoke(this.m_LoadFile, new object[] { e.FullPath });
        }

        /// <summary>
        /// Occurs when the file is deleted...
        /// </summary>
        /// <param name="sender">FileSystemWatcher</param>
        /// <param name="e">Events</param>
        void m_FSW_Deleted(object sender, FileSystemEventArgs e)
        {
            this.Invoke(this.m_CloseDel);
        }

        /// <summary>
        /// Close Delegate Method...
        /// </summary>
        private void DelClose ()
        {
            if (MessageBox.Show(this.m_MainForm, this.m_Editor.FileName + " has been deleted. Do you want to close this file's tab?",
                "Peter", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
            {
                this.m_Changed = false;
                this.CloseTab();
            }
        }

        /// <summary>
        /// Reload File Delegate...
        /// </summary>
        /// <param name="file">Path to File.</param>
        private void DelReLoad (string file)
        {
            if (MessageBox.Show(this.m_MainForm, this.m_Editor.FileName + " has changed. Do you want to reload the file?",
                "Peter", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
            {
                this.LoadFile(file);
            }
        }

        #endregion

        #region -= Book Marks =-

        /// <summary>
        /// Toggles a mark at the current line...
        /// </summary>
        public void ToggleMark()
        {
            this.m_Editor.Document.BookmarkManager.ToggleMarkAt(this.m_Editor.ActiveTextAreaControl.Caret.Line);
            this.m_Editor.ActiveTextAreaControl.Invalidate(true);
        }

        /// <summary>
        /// Removes all the Marks from the Edior...
        /// </summary>
        public void RemoveAllMarks()
        {
            this.m_Editor.Document.BookmarkManager.Clear();
            this.m_Editor.ActiveTextAreaControl.Invalidate(true);
        }

        /// <summary>
        /// Goes to the next(true) or previous(false) mark...
        /// </summary>
        /// <param name="forward">True(next) or Previous(false)</param>
        public void GotoMark(bool forward)
        {
            Bookmark b = (forward) ?
                this.m_Editor.Document.BookmarkManager.GetNextMark(this.m_Editor.ActiveTextAreaControl.Caret.Line) :
                this.m_Editor.Document.BookmarkManager.GetPrevMark(this.m_Editor.ActiveTextAreaControl.Caret.Line);
            this.m_Editor.ActiveTextAreaControl.CenterViewOn(b.LineNumber, 0);
            this.m_Editor.ActiveTextAreaControl.Caret.Line = b.LineNumber;
        }

        #endregion

        #region -= Setup Editor =-

        /// <summary>
        /// Sets up the Editor...
        /// </summary>
        /// <param name="node">XmlNode that holds the Configuration.</param>
        public void SetupEditor(Common.EditorConfig config)
        {
            this.m_Editor.ShowEOLMarkers = config.ShowEOL;
            this.m_Editor.ShowInvalidLines = config.ShowInvalidLines;
            this.m_Editor.ShowSpaces = config.ShowSpaces;
            this.m_Editor.ShowTabs = config.ShowTabs;
            this.m_Editor.ShowMatchingBracket = config.ShowMatchingBracket;
            this.m_Editor.ShowLineNumbers = config.ShowLineNumbers;
            this.m_Editor.ShowHRuler = config.ShowHRuler;
            this.m_Editor.ShowVRuler = config.ShowVRuler;
            this.m_Editor.EnableFolding = config.EnableCodeFolding;

            this.m_Editor.Font = config.EditorFont;
            this.m_Editor.ConvertTabsToSpaces = config.ConvertTabs;
            this.m_Editor.TabIndent = config.TabIndent;
            this.m_Editor.VRulerRow = config.VerticalRulerCol;
            this.m_Editor.UseAntiAliasFont = config.UseAntiAlias; // #develop 2
            /* // #develop 3
            if (config.UseAntiAlias)
            {
                this.m_Editor.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
            }*/
            this.m_Editor.AllowCaretBeyondEOL = config.AllowCaretBeyondEOL;
            this.m_Editor.TextEditorProperties.AutoInsertCurlyBracket = config.AutoInsertBracket;
            this.m_Editor.LineViewerStyle = (config.HighlightCurrentLine) ? LineViewerStyle.FullRow : LineViewerStyle.None;
            switch (config.BracketMatchingStyle.ToLower())
            {
                case "before":
                    this.m_Editor.BracketMatchingStyle = BracketMatchingStyle.Before;
                    break;
                case "after":
                    this.m_Editor.BracketMatchingStyle = BracketMatchingStyle.After;
                    break;
            }
            switch (config.IndentStyle.ToLower())
            {
                case "auto":
                    this.m_Editor.IndentStyle = IndentStyle.Auto;
                    break;
                case "none":
                    this.m_Editor.IndentStyle = IndentStyle.None;
                    break;
                case "smart":
                    this.m_Editor.IndentStyle = IndentStyle.Smart;
                    break;
            }
        }

        #endregion

        #region -= Drag N Drop =-

        /// <summary>
        /// Enables files to be dropped in the dock window...
        /// </summary>
        /// <param name="sender">Text Area</param>
        /// <param name="e">Events</param>
        private void TextArea_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true)
            {
                e.Effect = DragDropEffects.All;
            }
        }

        /// <summary>
        /// Grabs the files dropped in the Editor...
        /// </summary>
        /// <param name="sender">Text Area</param>
        /// <param name="e">Events</param>
        private void TextArea_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
            foreach (string file in files)
            {
                this.m_Host.CreateEditor(file, Path.GetFileName(file), this.Host.GetFileIcon(file, false), this);
            }
            this.m_MainForm.Focus();
        }

        #endregion

        #region -= Document Changed =-

        /// <summary>
        /// Occurs when the document changes...
        /// </summary>
        /// <param name="sender">Document</param>
        /// <param name="e">DocumentEvents</param>
        private void Document_DocumentChanged(object sender, DocumentEventArgs e)
        {
            if (!this.m_Changed)
            {
                this.TabText = "*" + this.TabText;
                this.m_Changed = true;
                this.m_MainForm.UpdateTitleBar();
            }
        }

        #endregion

        #region -= Highlighting =-

        /// <summary>
        /// Gets or Sets the Highligthing for the Editor...
        /// </summary>
        public string Highlighting
        {
            get { return this.m_Editor.Document.HighlightingStrategy.Name; }

            set
            {
                this.m_Editor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighter(value);
            }
        }

        #endregion

        #region -= Set/Get Text =-

        /// <summary>
        /// Sets the Text of the Editor...
        /// </summary>
        /// <param name="text">Text for the Editor</param>
        public void SetText(string text)
        {
            this.m_Editor.Document.TextContent = text;
            this.m_Changed = false;
            this.RemoveChangeStar();
        }

        /// <summary>
        /// Sets the Text of the Editor...
        /// </summary>
        /// <param name="text">Text for the Editor</param>
        public void SetTextChanged(string text)
        {
            this.m_Editor.Document.TextContent = text;
        }

        /// <summary>
        /// Gets the Text of the Editor...
        /// </summary>
        /// <returns>Text in the Editor</returns>
        public string GetText()
        {
            return this.m_Editor.Document.TextContent;
        }

        #endregion

        #region -= Get Persist String =-

        /// <summary>
        /// Overrides the Persist String for the Docking Control...
        /// </summary>
        /// <returns>Newly Formed Persist String.</returns>
        protected override string GetPersistString()
        {
            this.RemoveChangeStar();

            if (this.FileName == null)
            {
                return this.GetType().ToString() + "|" + this.TabText + "|none|" + this.m_Editor.Document.TextContent;
            }
            else
            {
                return this.GetType().ToString() + "|" + this.TabText + "|" + this.FileName + "|" + 
                    this.m_Editor.ActiveTextAreaControl.Caret.Offset.ToString() + "|" + this.m_Project;
            }
        }

        #endregion

        #region IPeterPluginTab Members

        /// <summary>
        /// Closes this Editor...
        /// </summary>
        public bool CloseTab()
        {
            if (this.m_Changed)
            {
                string file = (this.FileName == null) ? this.TabText : this.FileName;
                switch (MessageBox.Show(this.m_MainForm, "Do you want to Save " + file + "?", "Peter",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
                {
                    case DialogResult.Yes:
                        if (this.FileName == null)
                        {
                            this.m_Host.SaveAs(this);
                        }
                        else
                        {
                            this.Save();
                        }
                        break;
                    case DialogResult.No:
                        this.m_Changed = false;
                        break;
                    case DialogResult.Cancel:
                        return false;
                }
            }
            if(this.m_FSW != null)
                this.m_FSW.EnableRaisingEvents = false;
            this.Close();
            this.m_MainForm.UpdateCaretPos(0, 0, 0, null);
            this.Dispose(true);
            return true;
        }

        /// <summary>
        /// Saves the Current Document...
        /// </summary>
        public void Save()
        {
            this.SaveAs(this.m_Editor.FileName);
        }

        /// <summary>
        /// Saves the Document As...
        /// </summary>
        /// <param name="filePath">Path to File to Save As.</param>
        public void SaveAs(string filePath)
        {
            if(this.m_FSW != null)
                this.m_FSW.EnableRaisingEvents = false;

            if (string.IsNullOrEmpty(Path.GetExtension(filePath)))
                filePath += ".txt";

            FileInfo f = new FileInfo(filePath);
            if (f.Exists && f.IsReadOnly)
            {
                if (MessageBox.Show(this.m_MainForm, "The File \"" + filePath + "\" is Read Only.\nDo you want to save under a different file name?",
                    "Peter", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    this.m_Host.SaveAs(this);
                    return;
                }
                else
                {
                    return;
                }
            }
            
            this.ToolTipText = filePath;
            this.TabText = Path.GetFileName(filePath);
            this.Icon = this.m_Host.GetFileIcon(filePath, false);
            this.m_Editor.SaveFile(filePath);
            bool reload = false;
            if (string.IsNullOrEmpty(this.m_Editor.FileName))
            {
                reload = true;
            }
            else
            {
                if (Path.GetExtension(filePath) != Path.GetExtension(this.m_Editor.FileName))
                {
                    reload = true;
                }
            }

            if (reload)
            {
                this.m_Editor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighterForFile(filePath);
            }
            this.m_Changed = false;
            this.RemoveChangeStar();

            this.SetupFileWatcher();
        }

        /// <summary>
        /// Clipboard Cut Action...
        /// </summary>
        public void Cut()
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ClipboardHandler.Cut(null, null);
        }

        /// <summary>
        /// Clipboard Copy Action...
        /// </summary>
        public void Copy()
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ClipboardHandler.Copy(null, null);
        }

        /// <summary>
        /// Clipboard Paste Action...
        /// </summary>
        public void Paste()
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ClipboardHandler.Paste(null, null);
        }

        /// <summary>
        /// Edit Undo Action...
        /// </summary>
        public void Undo()
        {
            this.m_Editor.Document.UndoStack.Undo();
        }

        /// <summary>
        /// Edit Redo Action...
        /// </summary>
        public void Redo()
        {
            this.m_Editor.Document.UndoStack.Redo();
        }

        /// <summary>
        /// Clipboard Delete Action...
        /// </summary>
        public void Delete()
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ClipboardHandler.Delete(null, null);
        }

        public void Duplicate()
        {
            if (this.m_Editor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected)
            {
                string selection = this.m_Editor.ActiveTextAreaControl.SelectionManager.SelectedText;
                int pos = this.m_Editor.ActiveTextAreaControl.SelectionManager.SelectionCollection[0].EndOffset;
                this.m_Editor.Document.Insert(pos, selection);

                this.m_Editor.ActiveTextAreaControl.TextArea.Invalidate();
            }
        }

        /// <summary>
        /// Selects All the Text of the Document...
        /// </summary>
        public void SelectAll()
        {
            this.m_Editor.ActiveTextAreaControl.TextArea.ClipboardHandler.SelectAll(null, null);
        }

        /// <summary>
        /// Loads the Given File...
        /// </summary>
        /// <param name="filePath">Path to File.</param>
        public void LoadFile(string filePath)
        {
            FileInfo f = new FileInfo(filePath);
            this.TabText = f.Name;
            this.ToolTipText = filePath;
            this.m_Editor.LoadFile(filePath, true, true);
            this.m_Changed = false;
            this.RemoveChangeStar();

            if (string.IsNullOrEmpty(f.Extension))
            {
                this.m_Editor.Document.HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("HTML");
            }
            if (f.IsReadOnly)
            {
                this.m_Editor.Document.ReadOnly = true;
                Bitmap b = this.Icon.ToBitmap();
                using(Graphics g = Graphics.FromImage(b))
                {
                    Image img = this.m_MainForm.GetInternalImage("_lock");
                    g.DrawImage(img, new Point(0, 0));
                    this.Icon = Icon.FromHandle(b.GetHicon());
                }
            }
            this.SetupFileWatcher();
            this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// Marks all of the Occurances of the given Pattern...
        /// </summary>
        /// <param name="reg">Pattern to Mark.</param>
        public void MarkAll(Regex reg)
        {
            MatchCollection mc = reg.Matches(this.m_Editor.Document.TextContent);
            foreach (Match m in mc)
            {
                int line = this.m_Editor.Document.GetLineNumberForOffset(m.Index);
                this.m_Editor.Document.BookmarkManager.AddMark(new Bookmark(this.m_Editor.Document, line));
            }
            this.m_Editor.ActiveTextAreaControl.Invalidate(true);
            this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// Finds the Next Occurance of the given Pattern...
        /// </summary>
        /// <param name="reg">Pattern to Find.</param>
        public bool FindNext(Regex reg, bool searchUp)
        {
            this.m_Host.Trace("Searching for " + reg.ToString());
            Match m = null;
            if (searchUp)
            {
                MatchCollection mc = reg.Matches(this.m_Editor.Document.TextContent.Substring(0, this.m_Editor.ActiveTextAreaControl.Caret.Offset));
                if (mc.Count > 0)
                {
                    m = mc[mc.Count - 1];
                    HighlightMatch(m, searchUp);
                }
                else
                {
                    mc = reg.Matches(this.m_Editor.Document.TextContent);
                    if (mc.Count > 0)
                    {
                        m = mc[mc.Count - 1];
                        HighlightMatch(m, searchUp);
                    }
                    else
                    {
                        CouldNotFind(reg);
                        return false;
                    }
                }
            }
            else
            {
                m = reg.Match(this.m_Editor.Document.TextContent, this.m_Editor.ActiveTextAreaControl.Caret.Offset);
                if (!m.Success)
                {
                    m = reg.Match(this.m_Editor.Document.TextContent);
                }

                if (m.Success)
                {
                    HighlightMatch(m, searchUp);
                }
                else
                {
                    CouldNotFind(reg);
                    return false;
                }
                this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
            }

            return true;
        }

        private void CouldNotFind(Regex reg)
        {

            this.m_FindPos = -1;
            MessageBox.Show(this.m_MainForm, "No Occurrences of '" + reg.ToString() + "' found.", "Peter", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.m_Host.Trace("");
        }

        private void HighlightMatch(Match m, bool searchUp)
        {
            this.m_Editor.ActiveTextAreaControl.SelectionManager.SetSelection(
                this.m_Editor.Document.OffsetToPosition(m.Index), this.m_Editor.Document.OffsetToPosition(m.Index + m.Length));
            if (searchUp)
            {
                this.m_Editor.ActiveTextAreaControl.Caret.Position = this.m_Editor.Document.OffsetToPosition(m.Index);
            }
            else
            {
                this.m_Editor.ActiveTextAreaControl.Caret.Position = this.m_Editor.Document.OffsetToPosition(m.Index + m.Length);
            }
            this.m_Host.Trace("");
            this.m_FindPos = m.Index;
        }

        /// <summary>
        /// Replaces the Next Occurance of the Given Pattern...
        /// </summary>
        /// <param name="reg">Pattern to Replace.</param>
        public void ReplaceNext(Regex reg, string replaceWith, bool searchUp)
        {
            this.FindNext(reg, searchUp);
            if (this.m_FindPos != -1)
            {
                this.m_Editor.ActiveTextAreaControl.Caret.Position = this.m_Editor.Document.OffsetToPosition(this.m_FindPos);
                string replaced = reg.Replace(this.m_Editor.Document.TextContent, replaceWith, 1, this.m_FindPos);
                this.m_Editor.Document.Replace(0, this.m_Editor.Document.TextLength, replaced);
                this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
            }
            this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// Replaces all Occurances of the Given Pattern...
        /// </summary>
        /// <param name="reg">Pattern to Replace.</param>
        public void ReplaceAll(Regex reg, string replaceWith)
        {
            string replaced = reg.Replace(this.m_Editor.Document.TextContent, replaceWith);
            if (replaced != this.m_Editor.Document.TextContent)
            {
                this.m_Editor.Document.Replace(0, this.m_Editor.Document.TextLength, replaced);
            }
            else
            {
                this.m_Host.Trace("No Occurrences of '" + reg.ToString() + "' found in " + this.TabText + ".");
            }
            this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// Selects the word at the given offset...
        /// </summary>
        /// <param name="line">Line Word is on.</param>
        /// <param name="offset">Offset Word is at.</param>
        /// <param name="wordLeng">Length of Word.</param>
        public void SelectWord(int line, int offset, int wordLen)
        {
            this.m_Editor.ActiveTextAreaControl.ScrollTo(line);
            this.m_Editor.ActiveTextAreaControl.Caret.Line = line;
            this.m_Editor.ActiveTextAreaControl.SelectionManager.SetSelection(
                this.m_Editor.Document.OffsetToPosition(this.m_Editor.ActiveTextAreaControl.Caret.Offset + offset),
                this.m_Editor.Document.OffsetToPosition(this.m_Editor.ActiveTextAreaControl.Caret.Offset + offset + wordLen));
            this.m_Editor.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// Removes the * at the front of a changed document...
        /// </summary>
        private void RemoveChangeStar()
        {
            if (this.TabText.IndexOf('*') == 0)
            {
                this.TabText = this.TabText.Substring(1);
            }
        }

        /// <summary>
        /// Sets the Host Control...
        /// </summary>
        public IPeterPluginHost Host 
        {
            get { return this.m_Host; }

            set { this.m_Host = value; }
        }

        /// <summary>
        /// Gets the File Name of the Document...
        /// </summary>
        public string FileName
        {
            get { return this.m_Editor.FileName; }
        }

        /// <summary>
        /// Gets the Selected Text...
        /// </summary>
        public string Selection
        {
            get
            {
                if (this.m_Editor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected)
                {
                    return this.m_Editor.ActiveTextAreaControl.SelectionManager.SelectedText;
                }
                else
                {
                    return "";
                }
            }
        }

        /// <summary>
        /// Gets if we are able to do an Undo Action...
        /// </summary>
        public bool AbleToUndo
        {
            get { return this.m_Editor.EnableUndo; }
        }

        /// <summary>
        /// Gets if we are able to do a Redo Action...
        /// </summary>
        public bool AbleToRedo
        {
            get { return this.m_Editor.EnableRedo; }
        }

        /// <summary>
        /// Gets if the Editor needs to be Saved...
        /// </summary>
        public bool NeedsSaving
        {
            get { return this.m_Changed; }
        }

        /// <summary>
        /// Gets if this Control can Paste...
        /// </summary>
        public bool AbleToPaste
        {
            get { return true; }
        }

        /// <summary>
        /// Gets if this Control can Cut...
        /// </summary>
        public bool AbleToCut
        {
            get { return true; }
        }

        /// <summary>
        /// Gets if this Control can Cut...
        /// </summary>
        public bool AbleToCopy
        {
            get { return true; }
        }

        /// <summary>
        /// Gets if this Control can Select All...
        /// </summary>
        public bool AbleToSelectAll
        {
            get { return true; }
        }

        /// <summary>
        /// Gets if this Control can Save...
        /// </summary>
        public bool AbleToSave
        {
            get { return true; }
        }

        /// <summary>
        /// Gets if this Control can Delete...
        /// </summary>
        public bool AbleToDelete
        {
            get { return true; }
        }

        #endregion

        #region IHtmlInterface Members

        public void LinkClick(HtmlElement activeElement)
        {
            int line = 0;
            if (Int32.TryParse(activeElement.InnerText, out line))
            {
                --line;
                LineSegment lineSeg = this.m_Editor.Document.GetLineSegment(line);
                this.m_Editor.ActiveTextAreaControl.Caret.Position = this.m_Editor.Document.OffsetToPosition(lineSeg.Offset);
                this.m_Editor.ActiveTextAreaControl.CenterViewOn(line, 0);
            }
            else
            {
                string file = activeElement.GetAttribute("href");
                file = System.Web.HttpUtility.UrlDecode(file);
                file = file.Substring(8);
                file = file.Replace('/', '\\');
                string offset = activeElement.GetAttribute("offset");
                this.m_Host.CreateEditor(file, Path.GetFileName(file), this.Host.GetFileIcon(file, false), this);
                this.m_MainForm.GetEditor(file).ScrollTo(Convert.ToInt32(offset));
                this.m_MainForm.GetEditor(file).Project = this.m_Project;
            }
        }

        #endregion
    }
}
